package net.sf.xoperator.ui.trans;

import java.io.StringReader;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;

import net.sf.xoperator.Constants;
import net.sf.xoperator.blackboard.ConfigurationAwareKnowledgeSource;
import net.sf.xoperator.configuration.KSConfiguration;
import net.sf.xoperator.rdfxmpp.SPARQLQuery;
import net.sf.xoperator.rdfxmpp.SPARQLResult;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.openbbs.blackboard.filter.KindOfFilter;
import org.openbbs.blackboard.ks.KSExecutionContext;
/**
 * This class transforms an <code>SPQARLResult</code> from the Blackboard into a textual representation by applying a xsl transformation.
 * @author joerg
 *
 */
public class SPARQL2TextTransformer extends ConfigurationAwareKnowledgeSource{
	
	private Log log = LogFactory.getLog(SPARQL2TextTransformer.class); 
	
	private Transformer trans;
	/**
	 * transforms a string in the standard SPARQL resonse format into a String that can be read in a chat window. Makes use of a xsl stylesheet to make a transformation, thus these can be expansive, when dealing with large input data. 
	 * @param xml
	 * @return
	 */
	private String transformXML(String input){
		Source xml = new StreamSource(new StringReader(input));
		StringWriter text = new StringWriter();
		synchronized (this.trans) {
			try {
				this.trans.transform(xml, new StreamResult(text));
			} catch (TransformerException e) {
				this.log.error(Constants.ERR_XSL_001,e);
				text.append(Constants.ERR_XSL_001);
			}
		}
		
		return text.toString();
	}

	@Override
	public void configure(KSConfiguration config) throws Exception{
		SPARQL2TextConfig s2tconfig = (SPARQL2TextConfig) config;
		this.trans = TransformerFactory.newInstance().newTransformer(s2tconfig.getStyleSheetSource());
		
	}

	@Override
	public void executeInternal(KSExecutionContext context) {
		Set spresults = context.blackboard().readAll(new KindOfFilter(SPARQLResult.class));
		Set tresults = context.blackboard().readAll(new KindOfFilter(TransformedResult.class));
		
		for (Object otpresult : tresults) {
			TransformedResult tresult = (TransformedResult) otpresult;
			spresults.remove(tresult.getOrigResult());
		}
		
		for (Object object : spresults) {
			SPARQLResult spresult = (SPARQLResult) object;
			String txtresult = transformXML(spresult.getResult());
			
			context.blackboard().write(new TransformedResult(txtresult,spresult,spresult.getStoreName()));
		}
		
		
		
	}

	@Override
	public boolean isEnabledInternal(KSExecutionContext context) {
		
		Set results = context.blackboard().readAll(new KindOfFilter(SPARQLResult.class));
		Set transformedResults = context.blackboard().readAll(new KindOfFilter(TransformedResult.class)); 
		SPARQLQuery query = (SPARQLQuery) context.blackboard().read(new KindOfFilter(SPARQLQuery.class));
		
		
		
		return query!=null&&query.getOutputType().equals(SPARQLQuery.TXT_OUTPUT)&&results.size()>transformedResults.size();
		
		
	}

	@Override
	public List<Class<? extends KSConfiguration>> getConfigurationClasses() {
		List<Class<? extends KSConfiguration>> classes = new ArrayList<Class<? extends KSConfiguration>>();
		classes.add(SPARQL2TextConfig.class);
		return classes;
	}

}
